package com.spark.client;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.spark.client.builder.SparkBuilder;
import com.spark.client.config.SparkConfig;
import com.spark.client.exception.SparkClientException;
import com.spark.client.model.SparkRequest;
import com.spark.client.model.SparkResponse;
import com.spark.client.model.SparkMessage;
import com.spark.client.tool.SparkTool;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.*;
import java.util.function.Consumer;

/**
 * 星火大模型客户端
 * 支持流式和非流式调用，工具调用，链式配置
 */
@Component
public class SparkClient {
    
    private static final Logger logger = LoggerFactory.getLogger(SparkClient.class);
    private static final ObjectMapper objectMapper = new ObjectMapper();
    
    private final SparkConfig config;
    private final SparkRequest request;

    /**
     * 构造函数（通过 SparkBuilder 创建）
     */
    public SparkClient(SparkBuilder builder) {
        this.config = builder.getConfig();
        this.request = buildRequest(builder);
    }

    /**
     * 构造函数（直接使用配置）
     */
    public SparkClient(SparkConfig config) {
        this.config = config;
        this.request = new SparkRequest();
        initializeDefaultRequest();
    }

    /**
     * 创建构建器
     * @param config 配置对象
     * @return SparkBuilder
     */
    public static SparkBuilder builder(SparkConfig config) {
        return new SparkBuilder(config);
    }

    /**
     * 发送非流式请求
     * @return SparkResponse
     * @throws SparkClientException
     */
    public SparkResponse chat() throws SparkClientException {
        return chat(false);
    }

    /**
     * 发送请求
     * @param stream 是否流式
     * @return SparkResponse
     * @throws SparkClientException
     */
    public SparkResponse chat(boolean stream) throws SparkClientException {
        request.setStream(stream);
        
        if (config.getEnableLogging()) {
            logger.info("发送请求到星火大模型，模型: {}, 流式: {}", request.getModel(), stream);
            logger.debug("请求参数: {}", request);
        }
        
        try {
            String response = sendHttpRequest(request);
            
            if (stream) {
                // 流式响应处理
                return handleStreamResponse(response);
            } else {
                // 非流式响应处理
                SparkResponse sparkResponse = objectMapper.readValue(response, SparkResponse.class);
                
                if (config.getEnableLogging()) {
                    logger.info("收到响应，状态码: {}", sparkResponse.getCode());
                    if (sparkResponse.getUsage() != null) {
                        logger.info("Token 使用情况 - 输入: {}, 输出: {}, 总计: {}", 
                            sparkResponse.getUsage().getPromptTokens(),
                            sparkResponse.getUsage().getCompletionTokens(),
                            sparkResponse.getUsage().getTotalTokens());
                    }
                }
                
                return sparkResponse;
            }
        } catch (Exception e) {
            logger.error("请求星火大模型失败", e);
            throw new SparkClientException("请求失败: " + e.getMessage(), e);
        }
    }

    /**
     * 发送流式请求
     * @param callback 流式响应回调
     * @throws SparkClientException
     */
    public void chatStream(Consumer<SparkResponse> callback) throws SparkClientException {
        request.setStream(true);
        
        if (config.getEnableLogging()) {
            logger.info("发送流式请求到星火大模型，模型: {}", request.getModel());
        }
        
        try {
            sendStreamRequest(request, callback);
        } catch (Exception e) {
            logger.error("流式请求星火大模型失败", e);
            throw new SparkClientException("流式请求失败: " + e.getMessage(), e);
        }
    }

    /**
     * 添加消息并发送请求
     * @param message 用户消息
     * @return SparkResponse
     * @throws SparkClientException
     */
    public SparkResponse chat(String message) throws SparkClientException {
        request.getMessages().add(SparkMessage.user(message));
        return chat();
    }

    /**
     * 添加消息并发送流式请求
     * @param message 用户消息
     * @param callback 流式响应回调
     * @throws SparkClientException
     */
    public void chatStream(String message, Consumer<SparkResponse> callback) throws SparkClientException {
        request.getMessages().add(SparkMessage.user(message));
        chatStream(callback);
    }

    // 简化的便捷方法

    /**
     * 发送消息并直接获取内容（简化方法）
     * @param message 用户消息
     * @return 响应内容字符串
     * @throws SparkClientException
     */
    public String chatForContent(String message) throws SparkClientException {
        SparkResponse response = chat(message);
        if (response.isSuccess() && response.hasContent()) {
            return response.getContent();
        } else {
            throw new SparkClientException("获取响应内容失败: " + response.getErrorMessage());
        }
    }

    /**
     * 发送流式请求并处理内容（简化方法）
     * @param message 用户消息
     * @param contentCallback 内容回调（只接收有内容的部分）
     * @throws SparkClientException
     */
    public void chatStreamForContent(String message, Consumer<String> contentCallback) throws SparkClientException {
        request.getMessages().add(SparkMessage.user(message));
        chatStream(response -> {
            if (response.hasDeltaContent()) {
                contentCallback.accept(response.getDeltaContent());
            }
        });
    }

    /**
     * 发送流式请求并收集完整内容（简化方法）
     * @param message 用户消息
     * @param contentCallback 实时内容回调
     * @param completeCallback 完整内容回调
     * @throws SparkClientException
     */
    public void chatStreamWithComplete(String message, Consumer<String> contentCallback, Consumer<String> completeCallback) throws SparkClientException {
        StringBuilder fullContent = new StringBuilder();
        request.getMessages().add(SparkMessage.user(message));

        chatStream(response -> {
            if (response.hasDeltaContent()) {
                String deltaContent = response.getDeltaContent();
                fullContent.append(deltaContent);
                contentCallback.accept(deltaContent);

                // 检查是否完成
                if (response.getChoices() != null && !response.getChoices().isEmpty()) {
                    String finishReason = response.getChoices().get(0).getFinishReason();
                    if ("stop".equals(finishReason) || "length".equals(finishReason)) {
                        completeCallback.accept(fullContent.toString());
                    }
                }
            }
        });
    }

    /**
     * 构建请求对象
     */
    private SparkRequest buildRequest(SparkBuilder builder) {
        SparkRequest req = new SparkRequest();
        req.setModel(builder.getModel());
        req.setUser(builder.getUser());
        req.setMessages(new ArrayList<>(builder.getMessages()));
        req.setTemperature(builder.getTemperature());
        req.setTopP(builder.getTopP());
        req.setTopK(builder.getTopK());
        req.setPresencePenalty(builder.getPresencePenalty());
        req.setFrequencyPenalty(builder.getFrequencyPenalty());
        req.setStream(builder.getStream());
        req.setMaxTokens(builder.getMaxTokens());
        req.setResponseFormat(builder.getResponseFormat());
        req.setToolChoice(builder.getToolChoice());
        
        // 转换工具列表
        if (builder.getTools() != null && !builder.getTools().isEmpty()) {
            List<Map<String, Object>> tools = new ArrayList<>();
            for (SparkTool tool : builder.getTools()) {
                tools.add(convertToolToMap(tool));
            }
            req.setTools(tools);
        }
        
        return req;
    }

    /**
     * 初始化默认请求
     */
    private void initializeDefaultRequest() {
        request.setModel(config.getModel());
        request.setMaxTokens(config.getMaxTokens());
        request.setTemperature(config.getTemperature());
        request.setStream(false);
        request.setMessages(new ArrayList<>());
    }

    /**
     * 发送 HTTP 请求
     */
    private String sendHttpRequest(SparkRequest request) throws Exception {
        URL url = new URL(config.getBaseUrl());
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();

        // 设置请求方法和头部
        connection.setRequestMethod("POST");
        connection.setRequestProperty("Content-Type", "application/json");

        // 直接使用 Bearer Token 认证
        connection.setRequestProperty("Authorization", "Bearer " + config.getApiKey());

        connection.setDoOutput(true);
        connection.setConnectTimeout(config.getConnectTimeout());
        connection.setReadTimeout(config.getReadTimeout());

        // 发送请求体
        String requestBody = objectMapper.writeValueAsString(request);
        if (config.getEnableLogging()) {
            logger.debug("请求体: {}", requestBody);
        }

        try (OutputStream os = connection.getOutputStream()) {
            os.write(requestBody.getBytes("UTF-8"));
            os.flush();
        }

        // 读取响应
        int responseCode = connection.getResponseCode();
        if (config.getEnableLogging()) {
            logger.debug("响应状态码: {}", responseCode);
        }

        InputStream inputStream = responseCode >= 200 && responseCode < 300
            ? connection.getInputStream()
            : connection.getErrorStream();

        StringBuilder response = new StringBuilder();
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"))) {
            String line;
            while ((line = reader.readLine()) != null) {
                response.append(line);
            }
        }

        if (responseCode >= 400) {
            throw new SparkClientException("HTTP 错误: " + responseCode + ", 响应: " + response.toString());
        }

        return response.toString();
    }

    /**
     * 发送流式请求
     */
    private void sendStreamRequest(SparkRequest request, Consumer<SparkResponse> callback) throws Exception {
        URL url = new URL(config.getBaseUrl());
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();

        // 设置请求方法和头部
        connection.setRequestMethod("POST");
        connection.setRequestProperty("Content-Type", "application/json");

        // 直接使用 Bearer Token 认证
        connection.setRequestProperty("Authorization", "Bearer " + config.getApiKey());

        connection.setDoOutput(true);
        connection.setConnectTimeout(config.getConnectTimeout());
        connection.setReadTimeout(config.getReadTimeout());

        // 发送请求体
        String requestBody = objectMapper.writeValueAsString(request);
        try (OutputStream os = connection.getOutputStream()) {
            os.write(requestBody.getBytes("UTF-8"));
            os.flush();
        }

        // 读取流式响应
        int responseCode = connection.getResponseCode();
        if (responseCode >= 400) {
            try (BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getErrorStream(), "UTF-8"))) {
                StringBuilder errorResponse = new StringBuilder();
                String line;
                while ((line = reader.readLine()) != null) {
                    errorResponse.append(line);
                }
                throw new SparkClientException("HTTP 错误: " + responseCode + ", 响应: " + errorResponse.toString());
            }
        }

        try (BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"))) {
            String line;
            while ((line = reader.readLine()) != null) {
                if (line.startsWith("data:")) {
                    String data = line.substring(5).trim();
                    if ("[DONE]".equals(data)) {
                        break;
                    }

                    try {
                        SparkResponse response = objectMapper.readValue(data, SparkResponse.class);
                        callback.accept(response);
                    } catch (Exception e) {
                        if (config.getEnableLogging()) {
                            logger.warn("解析流式响应失败: {}", data, e);
                        }
                    }
                }
            }
        }
    }

    /**
     * 处理流式响应（非回调模式）
     */
    private SparkResponse handleStreamResponse(String response) throws Exception {
        // 这里简化处理，实际应该解析 SSE 格式
        return objectMapper.readValue(response, SparkResponse.class);
    }



    /**
     * 转换工具对象为 Map
     */
    private Map<String, Object> convertToolToMap(SparkTool tool) {
        Map<String, Object> toolMap = new HashMap<>();
        toolMap.put("type", tool.getType());

        if ("function".equals(tool.getType()) && tool.getFunction() != null) {
            Map<String, Object> functionMap = new HashMap<>();
            functionMap.put("name", tool.getFunction().getName());
            functionMap.put("description", tool.getFunction().getDescription());
            functionMap.put("parameters", tool.getFunction().getParameters());
            toolMap.put("function", functionMap);
        } else if ("web_search".equals(tool.getType()) && tool.getWebSearch() != null) {
            Map<String, Object> webSearchMap = new HashMap<>();
            webSearchMap.put("enable", tool.getWebSearch().getEnable());
            webSearchMap.put("show_ref_label", tool.getWebSearch().getShowRefLabel());
            webSearchMap.put("search_mode", tool.getWebSearch().getSearchMode());
            toolMap.put("web_search", webSearchMap);
        }

        return toolMap;
    }

    // Getters
    public SparkConfig getConfig() {
        return config;
    }

    public SparkRequest getRequest() {
        return request;
    }
}
